// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-08-20

package gen_annotation

import (
	"fmt"
	"gitee.com/go-libs/console"
	"html/template"
	"regexp"
	"sort"
	"time"
)

type (
	// ResultMiddleware
	// is a component for middleware annotation result.
	ResultMiddleware struct {
		Handlers         []*ResultMiddlewareHandler
		Package          string
		PackageList      []*ResultMiddlewareAlias
		Script, Datetime template.HTML

		aliasList   []string
		aliasMapper map[string]string
		aliasOffset int
	}

	// ResultMiddlewareAlias
	// is a component for package imports.
	ResultMiddlewareAlias struct {
		Alias string
		Pkg   string
	}

	// ResultMiddlewareHandler
	// is a component for handler executors.
	//
	//   var AnnotationMiddlewares = map[string]iris.Handler{
	//       "example": a0.ExampleMiddleware,
	//       "Example2Middleware": a1.Example2Middleware,
	//   }
	ResultMiddlewareHandler struct {
		Line int    // 24
		File string // app/middlewares/example_middleware.go
		Func string // ExampleMiddleware
		Name string // example
		Pkg  string // a0
	}
)

// NewResultMiddleware
// creates a middleware result component.
func NewResultMiddleware(command *console.Command, pkg string) *ResultMiddleware {
	return (&ResultMiddleware{
		Handlers:    make([]*ResultMiddlewareHandler, 0),
		Package:     pkg,
		PackageList: make([]*ResultMiddlewareAlias, 0),
	}).init(command)
}

// AddEntity
// add a middleware entity.
func (o *ResultMiddleware) AddEntity(entity *EntityMiddleware) {
	o.Handlers = append(o.Handlers, &ResultMiddlewareHandler{
		Line: entity.Line,
		File: entity.File,
		Func: entity.Func,
		Name: entity.Name,
		Pkg:  o.AddPackage(entity.Import, true),
	})
}

// AddPackage
// add a package import.
func (o *ResultMiddleware) AddPackage(pkg string, rename bool) (alias string) {
	pkg = regexp.MustCompile(`/+`).ReplaceAllString(pkg, `/`)

	// Reuse
	// previous alias name.
	if str, ok := o.aliasMapper[pkg]; ok {
		alias = str
		return
	}

	// Alias name generate.
	if rename {
		alias = fmt.Sprintf(`a%d`, o.aliasOffset)
		o.aliasOffset++
	}

	// Update alias mapping and list.
	o.aliasList = append(o.aliasList, pkg)
	o.aliasMapper[pkg] = alias

	// Update package info.
	return
}

// Ready
// is a hook when result ready.
func (o *ResultMiddleware) Ready() *ResultMiddleware {
	o.initPackages()
	return o
}

// +---------------------------------------------------------------------------+
// | Access methods                                                            |
// +---------------------------------------------------------------------------+

func (o *ResultMiddleware) init(command *console.Command) *ResultMiddleware {
	// Init
	// internal fields.
	o.aliasList = make([]string, 0)
	o.aliasMapper = make(map[string]string)

	// Init
	// basic fields.
	o.Datetime = template.HTML(time.Now().Format(time.RFC3339))
	o.Script = template.HTML(command.ToScript())

	// Add
	// builtin package.
	o.AddPackage("github.com/kataras/iris/v12", false)
	return o
}

func (o *ResultMiddleware) initPackages() {
	// Sort
	// package with alpha number.
	sort.Strings(o.aliasList)

	// Iterate
	// added packages then build package list.
	for _, pkg := range o.aliasList {
		// Build
		// alias component.
		item := &ResultMiddlewareAlias{Pkg: pkg}

		// Build
		// alias name.
		if alias, ok := o.aliasMapper[pkg]; ok {
			item.Alias = alias
		}

		// Add
		// to list.
		o.PackageList = append(o.PackageList, item)
	}
}
